import xID from "./xID.js";
import { replaceByObj,formatFileSize} from "./xUtil.js";
import {findJsonByCode} from "./treeUtil.js";
import xImage from "./xImage.js";

const tmplBase = `
        <div class="{{class}}">
             <div type="head" class="xhead"> 
                 <table>
                    <tbody type ="tbody"></tbody>
                 </table>                    
             </div>  
         <input type="file" id ="{{inputID}}" style="display: none;" accept="{{accept}}">     
        </div>`;

const tmplTr = '<tr>{{trHtml}}</tr>';
const tmplTd = '<td >{{tdHtml}}</td>';

const tmplFilename = `<span type="file-name" title="{{title}}">
                          <a href="{{url}}" download="{{filename}}">{{filename}}</a>
                       </span>`;
const tmplErrorname = `<span type="file-name" title="{{title}}"> {{filename}}
                       </span>`;
const tmplFilesize = '<span type ="file-size">{{filesize}}</span>';
const tmplPercent ='<span type="percent">{{percent}}</span>';
const tmplError ='<span type="error">上传失败</span>';
const tmplPlaceholder ='<span type ="placeholder">{{placeholder}}</span>';
const tmplUpload =`<i type="upload" class="iconfont icon-upload flat" title="上传" ></i>`;
const tmplUpdate =`<i type="update" class="iconfont icon-update flat" title="更新"></i>`;
const tmplImg = '<img type="img" {{src}}/>';
const tmplButtons ='{{upload}}{{update}}{{delete}}';
const tmplDelete ='<i type="delete" class="iconfont icon-delete flat" title="删除" ></i>';
const tmplId = 'id="{{id}}"';
const tmplItem = `
            <div type="item" {{id}}>
				<div type="item-main" >
				    {{filename}}
				    {{filesize}}
				    {{percent}}
				    {{error}}
				    {{placeholder}}
				    {{img}}
				</div>
				<div type="item-footer" class="btn-group">
				    {{buttons}}
				</div>
			</div>`
const tmplEmpty = `
            <div type="empty" >
               <div type="item-main" ></div>
			</div>`;


const tmplTitle = `title="{{title}}"`;

export default class xUpload {
    /* 定义变量 开始*/
    // jquery 对象
    $root;
    $head;
    $body;
    $input;
    $viewTitle;
    vUpload=[];
    vInputId = xID.getID();
    vUpdateItem;
    vBindEvent;
    vOffClickId = 'click.'+xID.getID();


    /* 定义变量 结束*/
    constructor(cfg) {
        this.$root = $('#' + cfg.el);
        this.$root.html(replaceByObj(tmplBase,{class:cfg.style||'upload',
            accept:cfg.accept||'',inputID:this.vInputId}));
        this.vCfg = cfg;
        this.init();
    };

    /* 渲染区块 开始 */
    init() {
        this.$head = this.$root.find('[type="head"]');
        this.$body = this.$root.find('[type="tbody"]');
        this.$input = this.$root.find('#'+this.vInputId);
        this.renderBody();
        this.$root.on('click','[type="upload"]',this.evUpload.bind(this));
        this.$root.on('click','[type="placeholder"]',this.evUpload.bind(this));
        this.$root.on('click','[type="update"]',this.evUpdate.bind(this));
        this.$root.on('click','[type="delete"]',this.evDelete.bind(this));
        this.$root.on('click','[type="img"]',this.evView.bind(this));
        this.$root.on('click','[type="file-name"]',this.evView.bind(this));
        this.$root.on('click',this.evActive.bind(this));
        this.$input.on('change',this.evInputChange.bind(this))

        let title ='';
        if(this.vCfg.title)
            title = tmplTitle.replace("{{title}}",this.vCfg.title);
        this.$head.attr("title",title);
    };

    renderStatus(action,status){
        if(action=='add'){
            this.$head.addClass(status);
        }else{
            this.$head.removeClass(status);
        }
    }

    initValue(value) {
        let tmp ;
        if(value){
            if(Array.isArray(value))
                tmp =[...value];
            else
                tmp = value.split(',');
            this.vUpload =[];
            tmp.forEach(item =>{
                this.vUpload.push({
                    filename:item,
                    code:xID.getID(),
                    url:item,
                    type:this.vCfg.type
                })
            })

        }else{
            this.vUpload =[];
        }
        this.renderBody();
        this.verify();
    }

    renderBody(){
        let trHtml ='';
        let tdHtml ='';
        // 0 代表可以无限增加
        let size = this.vCfg.size || 0;
        // 默认 每行一个
        let cols = this.vCfg.cols || 1;
        //必须几个 0 代表没有设置
        let fixed = this.vCfg.fixed || 0 ;
        let uploads = [...this.vUpload];
        if(size==0 || uploads.length<size)
            uploads.push({type:'upload',placeholder:this.vCfg.placeholder||''});
        let j = 0;
        for(let i =0;i<uploads.length;i++){
            let item = this.renderItem(uploads[i])
            tdHtml += tmplTd.replace('{{tdHtml}}',item);
            if((j==cols-1) || (i == uploads.length-1)){
                // 补齐
                if(j < cols-1){
                    for(let k=j;k<cols-1;k++)
                        tdHtml += tmplTd.replace('{{tdHtml}}',tmplEmpty);
                }
                trHtml += tmplTr.replace('trHtml',tdHtml)
                tdHtml = '';
                j=0;
            }else
                j=j+1;
        }
        this.$body.html(trHtml);
    }

    renderItem(item){
        let [id,filename,filesize,percent,error,buttons,placeholder,img] = ['','','','','','','','']
        switch(item.type){
            case 'file':
                id = this.renderId(item);
                filename =  this.renderFilename(item);
                filesize = this.renderFilesize(item);
                buttons = this.renderButtons(item);
                break;
            case 'uploading':
                id = this.renderId(item);
                filename =  this.renderFilename(item);
                percent = this.renderPercent(item);
                buttons = this.renderButtons(item);
                break;
            case 'upload':
                placeholder = this.renderPlaceholder();
                buttons = this.renderButtons(item);
                break;
            case 'error':
                id = this.renderId(item);
                filename =  this.renderFilename(item);
                error = tmplError;
                buttons = this.renderButtons(item);
                break;
            case 'image':
                id = this.renderId(item);
                img = this.renderImg(item);
                buttons = this.renderButtons(item);
                break;
        }
        return replaceByObj(tmplItem,{id,filename,filesize,percent,error,buttons,placeholder,img});
    }

    renderButtons(item){
        let html = '';
        switch(item.type){
            case 'upload':
                html = replaceByObj(tmplButtons,{upload:tmplUpload,delete:'',update:''})
                break;
            case 'uploading':
                html = replaceByObj(tmplButtons,{upload:'',delete:tmplDelete,update:''})
                break;
            case 'image':
            case 'file':
                html = replaceByObj(tmplButtons,{upload:'',delete:tmplDelete,update:tmplUpdate});
                break;
            case 'error':
                html = replaceByObj(tmplButtons,{upload:'',delete:tmplDelete,update:tmplUpdate});
                break;
        }
        return html;
    }

    renderFilename(item){
        if(item.type =='file')
            return replaceByObj(tmplFilename,{filename:item.localname||item.filename,
               title:item.localname||item.filename,url:item.url});
        else
            return replaceByObj(tmplErrorname,{filename:item.localname||item.filename,
                title:item.localname||item.filename});
    }

    renderFilesize(item){
        return tmplFilesize.replace("{{filesize}}",formatFileSize(item.filesize));
    }

    renderPercent(item){
        return tmplPercent.replace('{{percent}}',item.percent);
    }

    renderPlaceholder(item){
        if(this.vCfg.placeholder)
            return tmplPlaceholder.replace('{{placeholder}}',this.vCfg.placeholder)
        else
            return '';
    }

    renderImg(item){
        let src ='';
        if(item.url)
            src ='src="'+item.url+'"';
        return replaceByObj(tmplImg,{src});
    }

    renderId(item){
        return tmplId.replace('{{id}}',item.code)
    }

    evActive(e){
        this.renderStatus("add","active");
        $(document).on(this.vOffClickId,this.evOff.bind(this));
    }

    evUpload(e){
        this.vUpdateItem = null;
        this.$input[0].click();
    }

    evUpdate(e){
        let code = e.target.parentNode.parentNode.getAttribute("id");
        this.vUpdateItem = findJsonByCode(this.vUpload,code);
        this.$input[0].click();
    }

    evDelete(e){
        let code = e.target.parentNode.parentNode.getAttribute("id");
        let item = findJsonByCode(this.vUpload,code);
        if(item.xhr)
            item.xhr.abort()
        //删除
        this.vUpload = this.vUpload.filter(value => !(value==item))
        this.renderBody();
    }

    evView(e){
        xImage.pop($(e.target));
    }

    evInputChange(e){
        if(this.$input[0].files[0])
            this.UploadFile();
    }

    UploadFile(){
         // js 获取文件对象
        let url =  this.vCfg.url // 接收上传文件的后台地址
        let xhr = new XMLHttpRequest();
        let file = this.$input[0].files[0];
        let item;
        if(this.vUpdateItem){
            item = this.vUpdateItem;
            item.type ='uploading';
            item.localname = file.name;
            item.filename = file.name;
            item.filesize = file.size;
            item.filetype = file.type;
            item.xhr = xhr;
            item.percent = '0%';
        }
        else{
            item ={code:xID.getID(),type:"uploading",localname:file.name,filesize:file.size,
                filetype:file.type,xhr:xhr,percent:'0%',filename:file.name};
            this.vUpload.push(item);
        }

        let _this = this;
        let form = new FormData(); // FormData 对象
        form.append('file',file);
        xhr.addEventListener('readystatechange',function(e){
            _this.UploadChangeState.bind(_this)(e,item);
        });

        xhr.upload.addEventListener("progress", function(e){
            _this.UploadProgress.bind(_this)(e,item);
        });

        xhr.addEventListener("error", function(e){
            _this.UploadFailed.bind(_this)(e,item);
        })

        xhr.addEventListener("timeout", function(e){
            _this.UploadTimeout.bind(_this)(e,item);
        })

        xhr.open("POST", url,true);
        xhr.send(form)
        this.renderBody();
    }

    //progress 进度
    UploadProgress(e,item){
        let $percent = this.$root.find('#'+item.code+' [type="percent"]');
        item.percent = Math.round(e.loaded * 100 / e.total)+'%';
        $percent.html(item.percent);
    }

    // 上传失败
    UploadFailed(e,item) {
        item.type ='error';
        this.renderBody();
    }

    UploadTimeout(e,item) {
        item.type ='error';
        this.renderBody();
    }

    UploadChangeState(e,item){
        let xhr = item.xhr;
        if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 500){
            item.type ='error';
            this.renderBody();
        };
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status === 200) {
                let body = JSON.parse(xhr.responseText);
                item.filename = body.filename||body.FileName|| body.file_name||body.fileName;
                item.url = body.url||body.URL||(this.vCfg.path+'/'+item.filename) ;
                if(this.vCfg.type=='image')
                    item.type='image';
                else
                    item.type='file';
                item.xhr = null;
                this.renderBody();
                if(this.vBindEvent){
                    let files = this.vUpload.filter(value=>['file','image'].includes(value.type));
                    let values =[];
                    files.forEach(file => values.push(file.url));
                    this.vBindEvent(values.join(','));
                }
            }
        }
    };

    evOff(e) {
        if (this.$root.find(e.target).length <1){
            this.renderStatus("remove","active");
            this.verify();
            $(document).off(this.vOffClickId);
        }

    }

    setBindEvent(event) {
        this.vBindEvent = event;
    };

    setValue(value) {
        this.initValue(value);
    };


    verify() {
        let result = true;
        let tmp = this.vUpload.filter(value => ['file','image'].includes(value.type));
        if(this.vCfg.mandatory ){
            if(tmp.length<1){
                this.renderStatus("remove",'valid');
                this.renderStatus("add","invalid");
                result =false
            }else {
                this.renderStatus("remove",'invalid');
                this.renderStatus("add","valid");
            }
        }
        return result;
    }

    getValue() {
        return this.vUpload.filter(value => ['file','image'].includes(value.type));
    }

}